const { Service } = require("egg");

function buildTree(nodes, parent = 0) {
  return nodes
    .filter((node) => node.parentId === parent)
    .map((node) => ({
      ...node,
      children: buildTree(nodes, node.id),
    }));
}

class DirectoryService extends Service {
  async list() {
    const { app } = this;
    const allDirectories = await app.model.Directory.findAll({
      raw: true,
      attributes: ["id", "name", "parentId", "level", "status", "order", "creator"],
      order: [
        ["order", "ASC"],
        ["level", "ASC"],
      ],
    });
    return buildTree(allDirectories);
  }

  async create(directory) {
    if (
      directory.id &&
      directory.parentId &&
      directory.parentId === directory.id
    ) {
      throw new Error("参数有误，parentId和id一致");
    }
    // 确保level不超过3
    if (directory.level > 3) {
      throw new Error("栏目层级不能超过3级");
    }

    if (!directory.parentId) {
      directory.level = 1;
      directory.parentId = 0;
    } else {
      const parentExists = await this.findOne({ id: directory.parentId });
      if (!parentExists) {
        throw new Error("不存在父栏目");
      }
      directory.level = parentExists.level + 1;
    }
    if (directory.level > 3) {
      throw new Error("栏目层级不能超过3级");
    }

    const existingDirectory = await this.findOne({
      name: directory.name,
      parentId: directory.parentId,
    });

    if (existingDirectory) {
      throw new Error("同级别下已存在相同名称的栏目");
    }
    const { name, parentId, level } = directory;
    return await this.baseCreate({
      name,
      parentId,
      level,
      creator: directory.creator,
    });
  }

  async baseCreate(directory) {
    const { app } = this;

    const res = await app.model.Directory.findAll({
      where: {
        parentId: directory.parentId || 0,
      },
      order: [["order", "DESC"]],
      limit: 1,
    });
    const [maxOrderDirectory] = res || [];
    const order = maxOrderDirectory ? maxOrderDirectory.order : 0;
    return await app.model.Directory.create({
      name: directory.name,
      parentId: directory.parentId,
      level: directory.level,
      order: order + 1,
      creator: directory.creator,
    });
  }

  async createDirectories(category) {
    let currentLevel = 0;
    let directoryIds = [];
    let lastDirectoryInfo;
    const self = this;

    const topDirectory = await this.createAndIgnoreExist({
      name: category[0],
      parentId: 0,
      level: 0,
    });

    directoryIds.push(topDirectory.id);
    // let currentParentId = topDirectory.id;
    currentLevel = 1;

    async function iterateSubCategories(
      subCategory,
      directoryIds,
      currentLevel
    ) {
      if (subCategory.length === 0) return;

      for (const categoryName of subCategory) {
        let parentId = directoryIds[currentLevel - 1];
        if (!parentId) {
          console.error(`No parent directory found for level ${currentLevel}`);
          continue;
        }

        const directoryInfo = await self.createAndIgnoreExist({
          name: categoryName,
          parentId,
          level: currentLevel,
        });

        directoryIds.push(directoryInfo.id);
        currentLevel++;

        if (currentLevel < 4) {
          lastDirectoryInfo = directoryInfo;
          await iterateSubCategories(
            subCategory.slice(category.indexOf(categoryName) + 1),
            directoryIds,
            currentLevel
          );
        }
      }
    }

    await iterateSubCategories(category.slice(1), directoryIds, currentLevel);

    return lastDirectoryInfo;
  }

  // 处理批量导入
  async createAndIgnoreExist(directory) {
    if (
      directory.id &&
      directory.parentId &&
      directory.parentId === directory.id
    ) {
      throw new Error("参数有误，parentId和id一致");
    }
    // 确保level不超过3
    if (directory.level > 3) {
      throw new Error("栏目层级不能超过3级");
    }

    if (!directory.parentId) {
      directory.level = 1;
      directory.parentId = 0;
    } else {
      const parentExists = await this.findOne({ id: directory.parentId });
      if (!parentExists) {
        throw new Error("不存在父栏目");
      }
      directory.level = parentExists.level + 1;
    }
    if (directory.level > 3) {
      throw new Error("栏目层级不能超过3级");
    }

    const existingDirectory = await this.findOne({
      name: directory.name,
      parentId: directory.parentId,
    });

    if (existingDirectory) {
      return existingDirectory;
    }
    const { name, parentId, level } = directory;

    return await this.baseCreate({
      name,
      parentId,
      level,
      creator: directory.creator,
    });
  }

  async update(directory) {
    const { app } = this;

    const originalDirectory = await this.findOne({ id: directory.id });

    if (!originalDirectory) {
      throw new Error("原有的栏目不存在");
    }

    if (originalDirectory.parentId) {
      const parentExists = await this.findOne({ id: directory.parentId });
      if (!parentExists) {
        throw new Error("父栏目不存在");
      }
      if (directory.id && directory.parentId === directory.id) {
        throw new Error("参数有误，parentId和id一致");
      }
    }

    if (directory.level > 3) {
      throw new Error("栏目层级不能超过3级");
    }

    const where = {
      name: directory.name,
    };
    if (directory.parentId) {
      where.parentId = directory.parentId;
    }
    const existingDirectory = await app.model.Directory.findOne({
      where,
    });
    if (existingDirectory && existingDirectory.id !== directory.id) {
      throw new Error("同级别下已存在相同名称的栏目");
    }

    const updatedDirectory = await app.model.Directory.update(
      {
        name: directory.name,
      },
      {
        where: { id: directory.id },
      }
    );
    return updatedDirectory[0] ? updatedDirectory[0] : null;
  }

  async updateStatus(directory) {
    const { app } = this;
    const originalDirectory = await this.findOne({ id: directory.id });

    if (!originalDirectory) {
      throw new Error("原有的栏目不存在");
    }

    const updatedDirectory = await app.model.Directory.update(
      {
        status: directory.status ? 1 : 0,
      },
      {
        where: { id: directory.id },
      }
    );
    return updatedDirectory[0] ? updatedDirectory[0] : null;
  }
  async delete(id) {
    const { app } = this;
    return await app.model.Directory.destroy({
      where: { id },
    });
  }

  async findOne(where) {
    const { app } = this;
    const existingDirectory = await app.model.Directory.findOne({
      where,
    });
    return existingDirectory;
  }

  async setNextOrder({ id }) {
    const { ctx, app } = this;

    const originalDirectory = await this.findOne({ id });
    if (!originalDirectory) {
      throw new Error("栏目不存在");
    }
    const { parentId, order } = originalDirectory;
    const nextDirectory = await ctx.model.Directory.findOne({
      where: {
        parentId,
        order: order + 1,
      },
    });
    if (nextDirectory) {
      try {
        const res = await Promise.all([
          ctx.model.Directory.update(
            { order: order },
            { where: { id: nextDirectory.id } }
          ),
          ctx.model.Directory.update({ order: order + 1 }, { where: { id } }),
        ]);
        return res;
      } catch (error) {
        throw new Error("栏目调节顺序失败");
      }
    } else {
      throw new Error("栏目不存在，不能下移");
    }
  }

  async setPrevOrder({ id }) {
    const { ctx } = this;

    const originalDirectory = await this.findOne({ id });
    if (!originalDirectory) {
      throw new Error("栏目不存在");
    }
    const { parentId, order } = originalDirectory;
    const prevDirectory = await ctx.model.Directory.findOne({
      where: {
        parentId,
        order: order - 1,
      },
    });
    if (prevDirectory) {
      try {
        const res = await Promise.all([
          ctx.model.Directory.update(
            { order: order },
            { where: { id: prevDirectory.id } }
          ),
          ctx.model.Directory.update({ order: order - 1 }, { where: { id } }),
        ]);
        return res;
      } catch (error) {
        throw new Error(error);
      }
    } else {
      throw new Error("栏目不存在，不能下移");
    }
  }

  async navList() {
    const { app } = this;
    const allDirectories = await app.model.Directory.findAll({
      raw: true,
      attributes: ["id", "name", "parentId", "level", "status", "order"],
      where: {
        status: 1,
        level: {
          [app.Sequelize.Op.gt]: 0, // 大于0
          [app.Sequelize.Op.lt]: 3, // 小于3
        },
      },

      order: [
        ["order", "ASC"],
        ["level", "ASC"],
      ],
    });
    return buildTree(allDirectories);
  }
}

module.exports = DirectoryService;
